package pers.brozen.anka.support.wechat;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import pers.brozen.anka.support.wechat.request.MiniProgramSubscribeMessageSendParam;
import pers.brozen.anka.support.wechat.request.MiniProgramWXACodeParam;
import pers.brozen.anka.support.wechat.request.MiniProgramWXAQRCodeParam;
import pers.brozen.anka.support.wechat.request.OfficialAccountTemplateMessageSendParam;
import pers.brozen.anka.support.wechat.response.MiniProgramCode2SessionResult;
import pers.brozen.anka.utils.HttpClientHolder;
import pers.brozen.anka.utils.json.JacksonUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 小程序相关接口
 *
 * @author Brozen
 * @date 2019/8/15 3:15 PM
 */
@Slf4j
public class WeChatMiniProgramAPI extends WeChatAPI {

    public WeChatMiniProgramAPI(String appId, String appSecret) {
        super(appId, appSecret);
    }

    private final String ERROR_CODE = "500";

    /**
     * 小程序 使用jscode换取会话信息
     */
    public MiniProgramCode2SessionResult getSession(String jsCode) {
        HttpClient client = HttpClientHolder.getClient();
        String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                getAppId(), getAppSecret(), jsCode);

        try {
            HttpGet get = new HttpGet(url);
            HttpEntity entity = client.execute(get).getEntity();
            String response = EntityUtils.toString(entity, StandardCharsets.UTF_8);

            checkAndThrowErrorResponse(response);
            return JacksonUtils.parseObject(response, MiniProgramCode2SessionResult.class);
        } catch (IOException e) {
            log.error("获取会话异常", e);
            throw new WeChatException(ERROR_CODE, "网络访问异常！");
        }
    }

    /**
     * 获取小程序码
     */
    public ByteArrayOutputStream createWXACode(MiniProgramWXACodeParam param) {
        HttpClient client = HttpClientHolder.getClient();
        String accessToken = getAccessToken();
        String url = String.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s", accessToken);

        try {
            HttpPost post = new HttpPost(url);
            String entity = JacksonUtils.toJSONString(param);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            post.setEntity(new StringEntity(entity, StandardCharsets.UTF_8));

            HttpResponse response = client.execute(post);
            InputStream is = response.getEntity().getContent();
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            IOUtils.copy(is, byteOut);
            is.close();

            // 检测是否有错误码
            String responseStr = new String(byteOut.toByteArray());
            checkAndThrowErrorResponse(responseStr);

            return byteOut;
        } catch (IOException e) {
            log.error("获取access_token异常", e);
            throw new WeChatException(ERROR_CODE, "生成小程序码异常！", e);
        }
    }

    /**
     * 获取小程序二维码
     */
    public ByteArrayOutputStream createWXAQRCode(MiniProgramWXAQRCodeParam param) {
        HttpClient client = HttpClientHolder.getClient();
        String accessToken = getAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=%s", accessToken);

        try {
            HttpPost post = new HttpPost(url);
            String entity = JacksonUtils.toJSONString(param);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            post.setEntity(new StringEntity(entity, StandardCharsets.UTF_8));

            HttpResponse response = client.execute(post);
            InputStream is = response.getEntity().getContent();
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            IOUtils.copy(is, byteOut);
            is.close();

            // 检测是否有错误码
            String responseStr = new String(byteOut.toByteArray());
            checkAndThrowErrorResponse(responseStr);

            return byteOut;
        } catch (IOException e) {
            log.error("获取access_token异常", e);
            throw new WeChatException("500", "生成小程序二维码异常！", e);
        }
    }

    /**
     * 发送模板消息，可以使用小程序openId的同时使用公众号的appId 和 appSecret发送，会将消息从公众号中推送；
     * 前提条件是小程序与公众号关联，并在小程序开发平台中打开对公众号的消息推送；
     * <p>
     * 通过公众号给指定的用户发送模板消息，在60秒左右发送的模板消息超过60条，超过的消息发送成功但用户不能接收到
     */
    public void sendMessage(String openid, String template_id, String page, Map<String, OfficialAccountTemplateMessageSendParam.Data> data) {
        HttpClient client = HttpClientHolder.getClient();
        String accessToken = getAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s", accessToken);

        try {
            MiniProgramSubscribeMessageSendParam param = new MiniProgramSubscribeMessageSendParam();
            param.setAccess_token(accessToken);
            param.setTemplate_id(template_id);
            param.setPage(page);
            param.setTouser(openid);
            param.setData(data);

            HttpPost post = new HttpPost(url);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            post.setEntity(new StringEntity(JacksonUtils.toJSONString(param), StandardCharsets.UTF_8));

            HttpEntity responseEntity = client.execute(post).getEntity();
            String response = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);

            checkAndThrowErrorResponse(response);
        } catch (IOException e) {
            log.error("推送模板消息异常", e);
            throw new WeChatException("500", "网络访问异常！");
        }
    }

}
